package util;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

import users.Person;
import users.Role;
import users.UserAccount;
import books.Author;
import books.Book;
import books.BookInfo;
import books.BookInfoHome;
import books.BookRequestsInfo;
import books.BookReservation;
import books.Loan;
import books.Publisher;
import feedback.BookInfoFeedback;
import feedback.FeedbackComment;
import feedback.PersonFeedback;
import feedback.Rate;

/**
 * Removes all data from db.
 */
public class DbCleaner {

    private HibernateTemplate hibernateTemplate;

    @SuppressWarnings("unchecked")
    private List<Class<? extends Entity>> systemEntities = Arrays.asList(BookRequestsInfo.class,
            BookInfoFeedback.class, PersonFeedback.class, FeedbackComment.class, BookInfoHome.class,
            BookReservation.class, Loan.class, Book.class, BookInfo.class, Publisher.class, Rate.class, Person.class,
            UserAccount.class, Role.class, Author.class);

    public List<Class<? extends Entity>> getSystemEntities() {
        return this.systemEntities;
    }

    public void setSystemEntities(final List<Class<? extends Entity>> systemEntities) {
        this.systemEntities = systemEntities;
    }

    public final void setSessionFactory(final SessionFactory sessionFactory) {
        if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
            this.hibernateTemplate = new HibernateTemplate(sessionFactory);
        }
    }

    public void setHibernateTemplate(final HibernateTemplate hibernateTemplate) {
        this.hibernateTemplate = hibernateTemplate;
    }

    public HibernateTemplate getHibernateTemplate() {
        return this.hibernateTemplate;
    }

    @Transactional
    public void removeEntities(final Class<?> clazz) {
        this.getHibernateTemplate().execute(new HibernateCallback<Object>() {
            @Override
            public Integer doInHibernate(final Session session) throws HibernateException, SQLException {
                Query query = session.createQuery("delete from " + clazz.getName());
                return query.executeUpdate();
            }
        });
    }

    @Transactional
    public void removeTable(final String table) {
        this.getHibernateTemplate().execute(new HibernateCallback<Object>() {
            @Override
            public Object doInHibernate(final Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery("delete from " + table);
                return query.executeUpdate();
            }
        });
    }

    @Transactional
    public void removeAll() {
        this.removeTable("AUTHORS");
        this.removeTable("NOTIFICATIONLIST");
        this.removeTable("BORROWEDCOPIES");
        this.removeTable("AVAILABLECOPIES");
        for (Class<?> clazz : this.systemEntities) {
            this.removeEntities(clazz);
        }
    }
}
